/**
 * 
 */
package simulation;

import java.util.HashSet;

/**
 * @author aclayton
 *
 */
public class Rect {
	private double right, left, top, bottom;
	
	public Rect(double left, double right, double top, double bottom){
		this.right = right;
		this.left = left;
		this.top = top;
		this.bottom = bottom;
	}
	
	public boolean adjacentRect(Rect r){
		return right == r.left || left == r.right || top == r.bottom || bottom == r.top;
	}
	
	public Point getCenter(){
		return new Point((left + right)/2.0, (top-bottom)/2.0);
	}
	
	public double getRight(){
		return right;
	}
	
	public double getLeft(){
		return left;
	}
	
	public double getTop(){
		return top;
	}
	
	public double getBottom(){
		return bottom;
	}
	
	public double getHeight(){
		return top - bottom;
	}
	public double getWidth(){
		return right-left;
	}
	
	public double getArea(){
		return getHeight()*getWidth();
	}
	
	public LineSeg[] getSides(){
		LineSeg[] sides = new LineSeg[4];
		Point[] corners = getCorners();
		
		sides[0] = new LineSeg(corners[0], corners[1]);
		sides[1] = new LineSeg(corners[1], corners[2]);
		sides[2] = new LineSeg(corners[2], corners[3]);
		sides[3] = new LineSeg(corners[3], corners[0]);
		
		return sides;
	}
	
	public Point[] getCorners(){
		Point[] c = new Point[4];
		
		c[0] = new Point(left, bottom);
		c[1] = new Point(right, bottom);
		c[2] = new Point(left, top);
		c[3] = new Point(right, top);
		
		return c;
	}
	
	public double getHigher(double v1, double v2){
		if(v1>=v2)
			return v1;
		else
			return v2;
	}
	
	public double getLower(double v1, double v2){
		if(v1<=v2)
			return v1;
		else
			return v2;
	}
	
	public Rect union(Rect otherBox){
		
		return new Rect(getLower(left, otherBox.left), getHigher(right, otherBox.right), getHigher(top, otherBox.top), getLower(bottom, otherBox.bottom));
	}
	
	public boolean pointInBox(Point pt){
		return pt.getX() >= left && pt.getX() <= right && pt.getY() >= bottom && pt.getY() <= top; 
	}
	
	public boolean intersectsRect(Rect other){
		Point[] corners = other.getCorners();
		for(Point p : corners){
			if(pointInBox(p))
				return true;
		}
		
		corners = getCorners();
		for(Point p : corners){
			if(other.pointInBox(p))
				return true;
		}
		
		LineSeg[] sides = getSides(), othersides = other.getSides();
		for(LineSeg s : sides){
			for(LineSeg s2 : othersides){
				if(s.interectsSeg(s2))
					return true;
			}
		}
		
		return false;
	}
	
	public Rect[] splitVertically(){
		Rect[] splits = new Rect[2];
		Point center = getCenter();
		
		splits[0] = new Rect(left, center.getX(), top, bottom);
		splits[1] = new Rect(center.getX(), right, top, bottom);
		
		return splits;
	}
	
	public Rect[] splitHorizontally(){
		Rect[] splits = new Rect[2];
		Point center = getCenter();
		
		splits[0] = new Rect(left, right, top, center.getY());
		splits[1] = new Rect(left, right, center.getY(), bottom);
		
		return splits;
	}
	
	public HashSet<Rect> splitIntoNum(int numsplits){
		HashSet<Rect> splits = new HashSet<Rect>();
		
		splits.add(this);
		Rect temp[], largest;
		while(splits.size() < numsplits){
			largest = null;
			double largestArea = -1, area;
			for(Rect r : splits){
				area = r.getArea();
				if(largest == null || largestArea < area){
					largest = r;
					largestArea = area;
				}
			}
			
			splits.remove(largest);
			if(largest.getHeight()>largest.getWidth()){
				temp = largest.splitHorizontally();
			} else {
				temp = largest.splitVertically();
			}
			splits.add(temp[0]);
			splits.add(temp[1]);
			
		}
		
		return splits;
	}



	public boolean isEqualTo(Rect other) {
		if (this == other)
			return true;
		if (other == null)
			return false;
		if (bottom != other.bottom)
			return false;
		if (left != other.left)
			return false;
		if (right != other.right)
			return false;
		if (top != other.top)
			return false;
		return true;
	}
	

}
